package lookas.track;

import java.io.File;
import java.io.FileFilter;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import lookas.foto.FotoPosition;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Trip{
    private static final Log    log      = LogFactory.getLog(Trip.class);
    private Map<String, GPSPos> trasy    = new HashMap<String, GPSPos>();
    private File                fotosDir = null;
    private List<FotoPosition>  fotos    = new ArrayList<FotoPosition>();
    private long                delta    = 0;
    private String              dir      = null;

    class GPSPos extends LinkedList<GPSPosition>{
        private static final long serialVersionUID = 6142100333336273273L;
    }

    public void setFotosDir(File fotosDir){
        this.fotosDir = fotosDir;
        this.prepareFotos();
    }

    public void setDelta(long delta){
        this.delta = delta;
    }

    public Trip(){
        this.prepareTracks();
    }

    public Trip(String dbFile){
        DBFactory.setFile(dbFile);
        this.prepareTracks();
    }

    public Point getPointByDate(Date date){
        GPSPos pos = new GPSPos();
        Collection<GPSPos> values = trasy.values();
        for(GPSPos list: values){
            pos.addAll(list);
        }
        Collections.sort(pos);

        if(date.compareTo(pos.getLast().getDate()) > 0
            || date.compareTo(pos.getFirst().getDate()) < 0)
            return null;

        long timeMin = Long.MAX_VALUE;
        GPSPosition min = null;
        for(GPSPosition position: pos){
            long diff = Math.abs(position.getDate().getTime() - date.getTime());
            if(diff < timeMin){
                timeMin = diff;
                min = position;
            }else{
                return min.getPosition();
            }
        }
        return null;
    }

    public Map<String, GPSPos> getTrasy(){
        return trasy;
    }

    private void prepareFotos(){
        //        try{
        File[] files = fotosDir.listFiles(new FileFilter(){
            public boolean accept(File pathname){
                String[] split = pathname.getName().split("\\.");
                String roz = split[split.length - 1];
                if(roz.equals("jpg") || roz.equals("jpeg"))
                    return true;
                return false;
            }
        });

        for(int i = 0; i < files.length; i++){
            FotoPosition foto = null;
            try{
                foto = new FotoPosition(files[i], delta);
            }catch(Exception e){
                throw new RuntimeException(files[i].getName(), e);
            }
            Point point = getPointByDate(foto.getDate());
            if(point != null){
                foto.setPosition(point);
                fotos.add(foto);
            }else{
                log.info("Pominieto zdjecie " + files[i].getName());
            }
        }

    }

    private void prepareTracks(){
        PreparedStatement st;
        try{
            st = DBFactory.prepareStatement("SELECT data FROM TRACKS_V1");
            ResultSet rs = st.executeQuery();
            int x = 0;
            while(rs.next()){
                x++;
                GPSPos trasa = new GPSPos();
                byte[] obj = (byte[])rs.getObject(1);
                for(int i = 0; i < obj.length; i += 12){
                    long arr2long = arr2long(obj, i);
                    long arr2long2 = arr2long(obj, i + 8);
                    long arr2long3 = arr2long(obj, i + 4);
                    GPSPosition position = new GPSPosition(new Date(
                        arr2long * 1000), new Point(
                        (double)arr2long2 / 0x800000,
                        (double)arr2long3 / 0x800000));
                    trasa.add(position);
                }
                trasy.put("Trasa_" + x, trasa);
            }
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }

    public void setDir(String dir){
        this.dir = dir;
    }

    public void saveXML(String file) throws IOException{
        File outFile = new File(file);
        FileWriter out = new FileWriter(outFile);
        out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        out
            .write("<trip xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
        out
            .write("    xsi:noNamespaceSchemaLocation=\"http://nauka.googlecode.com/svn/trunk/JFotoGPS/res/tracks.xsd\">\n");
        if(fotos != null && fotos.size() > 0){
            out.write("<fotos>\n");
            for(FotoPosition foto: fotos){
                out.write(foto.toXML(dir) + "\n");
            }
            out.write("</fotos>\n");
        }
        out.write("<tracks>\n");
        for(String key: trasy.keySet()){
            out.write(String.format("<track name=\"%s\">\n", key));
            List<GPSPosition> trasa = trasy.get(key);
            for(GPSPosition position: trasa){
                out.write(position.toXML());
                out.write("\n");
            }
            out.write("</track>\n");
        }
        out.write("</tracks>\n");
        out.write("</trip>\n");
        out.close();
    }

    private long arr2long(byte[] b, int start){
        long l = 0;
        l |= b[start + 3] & 0xFF;
        l <<= 8;
        l |= b[start + 2] & 0xFF;
        l <<= 8;
        l |= b[start + 1] & 0xFF;
        l <<= 8;
        l |= b[start] & 0xFF;
        return l;
    }
}
